﻿using System;
using System.Collections.ObjectModel;
using System.Net;
using System.Data;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.Search.Administration;
using Microsoft.Office.Server.Search.Query;
using SharePointSearchBench.Library.Logging;

namespace SharePointSearchBench.Library
{
    /// <summary>
    /// The default context used for performing SharePoint searches.
    /// </summary>
    public class ServerSearchBenchContext : ISearchBenchContext
    {
        Search search;
        SPSite site;
        FullTextSqlQuery fullTextQuery;
        KeywordQuery keywordQuery;

        /// <summary>
        /// Creates a new instance of the class.
        /// </summary>
        /// <param name="search"></param>
        public ServerSearchBenchContext(Search search)
        {
            this.search = search;
        }

        /// <summary>
        /// Gets whether this context requires credentials to make calls.
        /// </summary>
        public bool RequiresCredentials { get { return false; } }

        /// <summary>
        /// Initializes the search state in preparation for a search operation.
        /// </summary>
        public void PrepareSearch()
        {
            using(IDisposableLogWriter debug = new DisposableDebugLogWriter("PrepareSearch"))
            {
                this.fullTextQuery = null;
                this.keywordQuery = null;
                this.site = null;

                if (search.SearchType == SearchType.FullText)
                {
                    debug.WriteMessage("Preparing full text search...");
                    this.PrepareFullTextSqlSearch();
                }
                else
                {
                    debug.WriteMessage("Preparing keyword search...");
                    this.PrepareKeywordSearch();
                }
            }
        }

        /// <summary>
        /// Performs a search operation and returns results.
        /// </summary>
        /// <returns></returns>
        public DataSet Execute()
        {
            using(IDisposableLogWriter debug = new DisposableDebugLogWriter("Execute"))
            {
                DataSet results = null;
                
                    if(search.SearchType == SearchType.FullText)
                    {
                        debug.WriteMessage("Executing full text search...");
                        ResultTableCollection resultTables = this.fullTextQuery.Execute();
                        results = this.search.CreateDataSetFromResults(resultTables);
                    }
                    else
                    {
                        debug.WriteMessage("Executing keyword search...");
                        ResultTableCollection resultTables = this.keywordQuery.Execute();
                        results = this.search.CreateDataSetFromResults(resultTables);
                    }
                
                debug.WriteMessage(string.Format("{0} results found.", results.Tables[0].Rows.Count.ToString()));
                return results;
            }
        }

        void PrepareFullTextSqlSearch()
        {
            string url = search.ContextUri.AbsoluteUri;
            if (url.EndsWith("/"))
            {
                url = url.Substring(0, url.Length - 1);
            }
            ResultType resultType = Search.GetSharePointResultType(this.search.SearchResultType);
            this.site = new SPSite(url);
            this.fullTextQuery = new FullTextSqlQuery(this.site);
            this.fullTextQuery.QueryText = this.search.SearchText.ToString();
            this.fullTextQuery.ResultTypes = resultType;
            this.fullTextQuery.StartRow = this.search.StartAt;
            this.fullTextQuery.RowLimit = this.search.ResultCount;
        }

        
        void PrepareKeywordSearch()
        {
            this.site = new SPSite(search.ContextUri.AbsoluteUri);
            this.keywordQuery = new KeywordQuery(this.site);
            this.keywordQuery.QueryText = this.search.SearchText.ToString();
            this.keywordQuery.ResultTypes = Search.GetSharePointResultType(this.search.SearchResultType);
            this.keywordQuery.StartRow = this.search.StartAt;
            this.keywordQuery.RowLimit = this.search.ResultCount;

            if(this.search.DisplayFields.Count > 0)
            {
                this.keywordQuery.SelectProperties.Clear();
                foreach(string field in this.search.DisplayFields)
                {
                    this.keywordQuery.SelectProperties.Add(field);
                }
            }

            if(this.search.SortFields.Count > 0)
            {
                this.keywordQuery.SortList.Clear();
                foreach(string field in search.SortFields)
                {
                    this.keywordQuery.SortList.Add(field, SortDirection.Ascending);
                }
            }
        }

        void PrepareServiceSearch()
        {
        }

       

        /// <summary>
        /// Obtains a collection of <see cref="SearchProperty"/> objects 
        /// using the SharePoint object model.  
        /// </summary>
        /// <returns></returns>
        public Collection<SearchProperty> GetSearchProperties()
        {
            SPSite site = new SPSite(this.search.ContextUri.AbsoluteUri);
            Query q = new KeywordQuery(site);
            PropertyInformation[] properties = q.GetProperties();
            Collection<SearchProperty> results = new Collection<SearchProperty>();
            foreach(PropertyInformation property in properties)
            {
                results.Add(new SearchProperty(property));
            }
            return results;
        }

        ///// <summary>
        ///// Obtains a collection of <see cref="SearchProperty"/> objects using
        ///// the SharePoint Search service.
        ///// </summary>
        ///// <returns></returns>
        //public Collection<SearchProperty> GetSearchPropertiesByService()
        //{
        //    QueryService.QueryService client = ServerSearchBenchContext.GetService(this.search.Credentials, this.search.ContextUri);
        //    client.Credentials = this.search.Credentials;
        //    client.Url = this.search.ContextUri.AbsoluteUri;
        //    DataSet metadata = client.GetSearchMetadata();
        //    Collection<SearchProperty> properties = SearchProperty.GetPropertiesFromRawDataSet(metadata);
        //    return properties;
        //}

        ///// <summary>
        ///// Obtains a collection of <see cref="SearchScope"/> objects using
        ///// the SharePoint Search service.
        ///// </summary>
        ///// <returns></returns>
        //public Collection<SearchScope> GetScopesByService()
        //{
        //    QueryService.QueryService client = ServerSearchBenchContext.GetService(this.search.Credentials, this.search.ContextUri);
        //    client.Credentials = this.search.Credentials;
        //    client.Url = this.search.ContextUri.AbsoluteUri;
        //    DataSet metadata = client.GetSearchMetadata();
        //    Collection<SearchScope> scopes = SearchScope.GetScopesFromRawDataSet(metadata);
        //    return scopes;
        //}

        /// <summary>
        /// Obtains a collection of <see cref="SearchScope"/> objects using
        /// the SharePoint object model.
        /// </summary>
        /// <returns></returns>
        public Collection<SearchScope> GetScopes()
        {
            SearchContext context = SearchContext.GetContext(new SPSite(this.search.ContextUri.AbsoluteUri));
            Scopes contextScopes = new Scopes(context);
            Collection<SearchScope> scopes = new Collection<SearchScope>();
            foreach(Scope scope in contextScopes.AllScopes)
            {
                scopes.Add(new SearchScope(scope));
            }
            return scopes;
        }
    }
}
